

#include "ThreadPool.h"
using namespace std;
std::unique_ptr<ThreadPool> ThreadPool::instance = nullptr;
std::mutex ThreadPool::instanceMutex;
ThreadPool::ThreadPool() :ThreadPool(thread::hardware_concurrency()){
}

ThreadPool::ThreadPool(int size) {
    m_stop = false;
    for (int i=0;i<size;++i) {
        m_threads.emplace_back([this] {
            while (true) {
                function<void()> task;
                {
                    unique_lock<mutex> lock(m_taskMutex);
                    m_cv.wait(lock,[this]{return !m_tasks.empty()|| m_stop;});
                    if (m_stop|| m_tasks.empty()) {
                        return;
                    }
                    task = move(m_tasks.front());
                    m_tasks.pop();
                }
                task();
            }
        });
    }
}

ThreadPool::~ThreadPool() {
    {
        unique_lock<mutex> lock(m_taskMutex);
        m_stop=true;
    }
    m_cv.notify_all();
    for (auto& thread:m_threads) {
        thread.join();
    }
}


void ThreadPool::addTask(function<void()> task) {
    {
        unique_lock<mutex> lock(m_taskMutex);
        m_tasks.push(std::move(task));
    }
    m_cv.notify_one();
}

ThreadPool * ThreadPool::getInstance() {
    if (instance==nullptr) {
        unique_lock<mutex> lock(instanceMutex);
        if (instance==nullptr) {
            instance = unique_ptr<ThreadPool>(new ThreadPool());
        }
    }
    return instance.get();
}



